import sys
sys.path.append('.')

from utils import *

import glob
import numpy
import pylab
#import asa
import scipy.optimize,scipy.stats
import random
import os

import pyximport
pyximport.install()
import pwFunc
from pyevolve import G1DList
from pyevolve import GSimpleGA
from pyevolve import Selectors,Scaling
from pyevolve import Mutators
from pyevolve import Initializators
from pyevolve import GAllele,Consts
from pyevolve import FunctionSlot
    
class EvalF:
    def __init__(self,called,args=()):
        self.args=args
        self.func_name='wrapped'
        self.func_doc='doc wrapped'
        self.called=called
    def __call__(self,params):
        arglist=([numpy.array(list(params))]+list(self.args))
        return self.called(*tuple(arglist))


def tmkdir(path):
    try:
        os.mkdir(path)
    except:pass

def Labels(f):
    chunks=f.split('_')
    last=chunks.index('repeat')
    return chunks[1:last]

def DistinctLabel(f,files,sep='.'):
    common_labels=set.intersection(*tuple(map(lambda x:set(Labels(x)),files)))
    dlabels=set(Labels(f))-common_labels
    ldlabels=sorted(list(dlabels))
    return sep.join(ldlabels)


def gS(x,pieces=20):
    return numpy.linspace(x.min(),x.max(),pieces)

def lsSlope(x,y):
    xm=numpy.mean(x)
    ym=numpy.mean(y)
    return numpy.dot(y-ym,x-xm)/numpy.dot(x-xm,x-xm)
    

def gparamsS(y,x,S,pieces=20):
    xinit=[1.0/lsSlope(x,y)]
    xmin=[0.2*xinit[0]]
    xmax=[3.3*xinit[0]]
    zinit=[]
    zmin=[]
    zmax=[]
    for i in range(len(S)-1):
        ix=numpy.where((x>=S[i])*(x<=S[i+1]))
        local_x=x[ix]
        local_y=y[ix]
        xinit.append(numpy.mean(local_y))
        xmin.append(min(local_y))
        #xmax.append(min(local_y)+0.33*(max(local_y)-min(local_y)))
        #xmax.append(min(local_y)+0.8*(max(local_y)-min(local_y)))
        xmax.append(scipy.stats.scoreatpercentile(local_y,50))
        tspan=(max(local_y)-min(local_y))
        tmax=scipy.stats.scoreatpercentile(local_y-min(local_y),70)
        #tmin=scipy.stats.scoreatpercentile(local_y-min(local_y),1)
        zinit.append(1/(tspan*0.4))
        zmin.append(1.0/(tmax*1.0))
        zmax.append(1.0/(0.08*tmax))
        #zmax.append(1.0/(0.1*tspan))

    xinit.extend(zinit)
    xmin.extend(zmin)
    xmax.extend(zmax)
    return numpy.array(xinit),numpy.array(xmin),numpy.array(xmax)

def printParams(params,S,xm,ym,params_min,params_max,Unit=1,label=""):
    N=(len(params)-1)/2
    M=len(S)
    xm_rate=1.0/lsSlope(xm,ym)
    print 
    print "Rate:%s\t %4.3f[%4.3f] limits:[%4.3f, %4.3f] R_0:%4.3f[%4.3f]"%\
        (label,\
             params[0],params[0]/Unit,\
             params_min[0],params_max[0],\
             xm_rate,xm_rate/Unit)
    for i in range(N):
        print "range:\t [%4.1f, %4.1f]\t t0:\t %4.3f\t [%4.3f, %4.3f] \t mode:\t %4.3f\t [%4.3f, %4.3f]"%\
            (S[i],S[i+1],params[i+1],params_min[i+1],params_max[i+1],\
                 1.0/params[N+i+1],1.0/params_max[N+i+1],1.0/params_min[N+i+1])


def GAFindParams(x,y,S,xmin,xmax,generations=300,stats=30,popsize=100):
    N=len(xmin)
    setOfAlleles = GAllele.GAlleles()
    for i in xrange(N):
        setOfAlleles.add(GAllele.GAlleleRange(xmin[i],xmax[i],real=True))
    genome = G1DList.G1DList(N)
    genome.setParams(allele=setOfAlleles)
    eval_func=EvalF(pwFunc.GApErlangLikelyhood,args=(x,y,S))
    genome.evaluator.set(eval_func)
    genome.mutator.set(Mutators.G1DListMutatorAllele)
    genome.initializator.set(Initializators.G1DListInitializatorAllele)
    ga = GSimpleGA.GSimpleGA(genome)
    ga.minimax = Consts.minimaxType["maximize"]
    ga.selector.set(Selectors.GRouletteWheel)
    gpop=ga.getPopulation()
    gpop.scaleMethod.set(Scaling.SigmaTruncScaling)
    gpop.setPopulationSize(popsize)
    ga.setMultiProcessing(True)
    ga.setGenerations(generations)
    ga.evolve(freq_stats=stats)
    result=numpy.array(list(ga.bestIndividual()))
    """
    if tnc:
        params_tnc,nfeval,rc=scipy.optimize.fmin_tnc(pwFunc.pErlangLikelyhood,
                                                     result,
                                                     args=(x,y,S),
                                                     approx_grad=1,
                                                     maxfun=10000,disp=1)
        return params_tnc
    else:
    """
    return result
    


if __name__=='__main__':
    if not globals().has_key('files'):
        files=glob.glob('data/*.log')
        FileIndex=0
        ResultsDict={}
    else:FileIndex+=1
    File=files[FileIndex]
    figname=os.path.join('Plots',os.path.basename(File).replace('log','pdf'))
    if os.access(figname,os.R_OK):
        raise IOError
    print File
    data=LoadFile(File)
    sizes=data[:,1]
    WCTimes=data[:,3]
    IOTimes=data[:,5]
    rusage=data[:,6]
    rates=data[:,8]
    MRUTimes=data[:,7]
    ix=numpy.argsort(sizes)
    Sizes    = numpy.array(sizes)[ix]
    WCTimes  = numpy.array(WCTimes)[ix]
    CPUTimes = numpy.array(rusage)[ix]
    IOwait   = numpy.array(IOTimes)[ix]
    Rates    = numpy.array(rates)[ix]
    MRUTimes   = numpy.array(MRUTimes)[ix]
    Unit=0.012
    psize=1
    pieces=10
    x=Sizes

    #y=IOwait/Unit; FigLabel="IOw"
    #y1=WCTimes/Unit;FigLabel1="WTC"
    y=WCTimes/Unit; FigLabel="WTC"
    y1=IOwait/Unit; FigLabel1="IOw"

    tmkdir('Plots')
    S=gS(x,pieces=pieces)
    xinit,xmin,xmax=gparamsS(y,x,S,pieces=pieces)

    popsize=max(Consts.CDefGAPopulationSize,20*pieces)
    
    params=GAFindParams(x,y,S,xmin,xmax,generations=300,stats=100,popsize=popsize)
    ResultsDict[File]=(S,params)
    save(ResultsDict,"ResultsDict.pickle")

    X=numpy.linspace(x.min(),x.max(),100*pieces)
    Y=pwFunc.gExpectedFunc(X,S,params)
    Ymode=pwFunc.gModeFunc(X,S,params)
    Ymin=pwFunc.gMinFunc(X,S,params)

    n=(len(params)-1)/2
    xEx=(S[:-1]+S[1:])*0.5
    yEx=params[1:n+1]
    xm_rate=1.0/lsSlope(xEx,yEx)    
    Rm=1.0/(1.0/params[0]+1.0/(xm_rate))

    printParams(params,S,xEx,yEx,xmin,xmax,Unit=Unit,label=FigLabel+":avg")
    fig=pylab.figure(num=6,figsize=(15,8))
    pylab.ion()
    pylab.clf()
    pylab.grid(True)
    pylab.xlabel('Size[MB]')
    uplim=scipy.stats.scoreatpercentile(y,99.9)
    yl='Time[seek]' if Unit<1 else 'Time[s]'
    pylab.ylabel(yl)
    pylab.plot(x,y,linestyle='None',marker='.',markersize=psize,alpha=0.3,label=("%s"%FigLabel))
    pylab.plot(x,y1,linestyle='None',marker='.',markersize=psize,alpha=0.3,label=FigLabel1)

    pylab.plot(X,Y,'-',label=('GA,Expected:%s'%FigLabel),linewidth=2.0)
    pylab.plot(X,Ymode,'-',label=('GA,Mode:%s'%FigLabel),linewidth=2.0)
    pylab.plot(X,Ymin,'-',label=('GA,Min:%s'%FigLabel),linewidth=2.0)
    #pylab.plot(X,Ymode[0]+X/params[0],'-',label=('GA,R:%s'%FigLabel),linewidth=3.0)
    #pylab.plot(X,Ymode[0]+X/xm_rate,'-',label=('GA,T0:%s'%FigLabel),linewidth=3.0)    
    #pylab.plot(X,Ymode[0]+X/Rm,'-',label=('GA,Rmix:%s'%FigLabel),linewidth=3.0)
    pylab.plot(X,Y[0]+X/Rm,'-',label=('GA,Rmix:%s'%FigLabel),linewidth=3.0)

    #pylab.plot(X,Y_tnc,'.-',label='tnc')
    pylab.ylim((0,uplim))
    pylab.legend()
    
    pylab.title(DistinctLabel(File,files,sep=' '))
    figname=os.path.join('Plots',os.path.basename(File).replace('log','pdf'))
    pylab.savefig(figname)
    figname=os.path.join('Plots',os.path.basename(File).replace('log','png'))
    pylab.savefig(figname)
